package com.jb.util;

import com.jb.demo.forum.domain.Forum;
import com.jb.framework.util.PropUtil;

import java.beans.PropertyDescriptor;

import java.io.File;

import java.net.URL;
import java.net.URLClassLoader;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ClassUtil {
    protected static Log log = LogFactory.getLog(ClassUtil.class.getName());
    //load classes, from dirName
    private Class clazz=Forum.class;
 
    public void setClassName(String className) {
        clazz = getClass(className);
    }
    public static Object createInstance(String className, String dirName) {
        // Get the directory (URL) of the reloadable class
        URL[] urls = null;

        try {
            // Convert the file object to a URL
            File dir = new File(dirName + File.separator);
            URL url = dir.toURL();
            urls = new URL[] { url };

            ClassLoader cl = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
            
            // Load in the class
            Class cls = cl.loadClass(className);
            //this could fails due to security
            return cls.newInstance();
        } catch (Throwable e) {
            try {
                return createInstance(className);
            }catch(Throwable _e)
            {
               if(log.isErrorEnabled())
                   log.error(ClassUtil.class, _e);
            }
        }

        return null;
    }
    
    /**
     * Factory method that creates a object.
     *
     * @param clazz Class of the object to be created.
     *
     * @return newly created object.
     */
    public static Object createInstance(Class clazz) {
        try {
            return clazz.newInstance();
        } catch (Throwable e) {
            return null;
        }
    }

    public static Class getClass(String className) {
        try {
            return Class.forName(className);
        } catch (Throwable e) {
            return null;
        }
    }

    public static Object createInstance(String className) {
        return new ClassUtil()._createInstance(className);
    }
    private Object _createInstance(String className) {
        try {
            ClassLoader myCL = getLoader();
            return myCL.loadClass(className).newInstance();
        } catch (InstantiationException e) {
            if(log.isErrorEnabled())
                log.error(this, e);
        } catch (IllegalAccessException e) {
            if(log.isErrorEnabled())
                log.error(this, e);

        } catch (ClassNotFoundException e) {
            if(log.isErrorEnabled())
                log.error(this, e);

        }
        return null;
    }
    public static ClassLoader getLoader() {
        return Thread.currentThread().getContextClassLoader();
    }
   
    public Iterator list(ClassLoader CL) {
        try {
            Class CL_class = CL.getClass();
            while (CL_class != java.lang.ClassLoader.class) {
                CL_class = CL_class.getSuperclass();
            }

            java.lang.reflect.Field ClassLoader_classes_field = 
                CL_class.getDeclaredField("classes");
            ClassLoader_classes_field.setAccessible(true);
            Vector classes = (Vector)ClassLoader_classes_field.get(CL);
            return classes.iterator();
        } catch (SecurityException e) {
            return Collections.emptyList().iterator();
        } catch (IllegalArgumentException e) {
            return Collections.emptyList().iterator();

        } catch (NoSuchFieldException e) {
            return Collections.emptyList().iterator();

        } catch (IllegalAccessException e) {
            return Collections.emptyList().iterator();
            
        }
    }
    
    static List <Klass> loadedClasses = new ArrayList<Klass>();
    public List <Klass>getLoadedClasses()  {
        if(loadedClasses.size()==0)
        {
            ClassLoader myCL = getLoader();
            //Thread.currentThread().getContextClassLoader();
            while (myCL != null) {
                for (Iterator iter = list(myCL); iter.hasNext(); ) {
                    Class klass = (Class)iter.next();
                    if (klass.getName().startsWith("com.jb"))
                        loadedClasses.add(new Klass((Class)iter.next()));
                }
                myCL = myCL.getParent();
            }
        }
        return loadedClasses;
    }
    
    public static void main(String[] args) {
        List classes = new ClassUtil().getLoadedClasses();
        for(Object klass : classes) {
            if(klass instanceof Class)
            { 
                System.err.println(((Class)klass).getName());
            }
        } 
        
    }

    public void setClazz(Class param) {
        this.clazz = param;
    }

    public Class getClazz() {
        return clazz;
    }
    
    public List<PropertyDescriptor> getProperties() {
        return PropUtil.getProperties(clazz);
    }
}
